<?php
/**
 * Created by PhpStorm.
 * User: kcswag
 * Date: 12/10/17
 * Time: 9:59 AM
 */

namespace AppBundle\Utils;


use Symfony\Component\Config\Definition\Exception\Exception;

class Curl
{
    protected $ch = null;
    protected $errorCode = 0;
    protected $errorMsg = '';
    protected $curlInfo = array();
    protected $verbose = null;
    private static $instance = null;

    public function getLastErrorCode()
    {
        return $this->errorCode;
    }

    public function getLastErrorMsg()
    {
        return $this->errorMsg;
    }

    public function getLastCurlInfo()
    {
        return $this->curlInfo;
    }

    private function __construct()
    {
        $this->ch = curl_init();
    }

    private function __clone(){
        throw new Exception('The Curl library cannot be cloned');
    }

    public static function getInstance(){
        if(!self::$instance instanceof self){
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function get($url, $params = [], $headers = [], $timeout = 3, $httpVersion = CURL_HTTP_VERSION_1_1)
    {
        $url = $this->buildQuery($url,$params);
        $this->setGeneralOption($url,$timeout,$headers,$httpVersion);
        $result = $this->execute();
        return $result;
    }

    public function post($url, $params = [], $headers = [], $withHttpBuildQuery = false, $timeout=3, $httpVersion = CURL_HTTP_VERSION_1_1)
    {
        if ($withHttpBuildQuery) {
            if (!is_array($params)) {
                $params = [$params];
            }
            $params = http_build_query($params);
        }

        curl_setopt($this->ch, CURLOPT_POST, 1);
        curl_setopt($this->ch, CURLOPT_POSTFIELDS, $params);
        $this->setGeneralOption($url,$timeout,$headers, $httpVersion);
        $result = $this->execute();
        return $result;
    }


    public function __destruct()
    {
        $this->close();
    }

    public function close()
    {
        if (is_resource($this->ch)) {
            curl_close($this->ch);
            $this->ch = null;
        }
    }

    protected function buildQuery($url,$params)
    {
        if (!$params) {
            return $url;
        }

        if (strpos($url, '?') === false) {
            $url .= '?';
        } else {
            $url .= '&';
        }

        $url .= http_build_query($params);
        return $url;
    }

    protected function setGeneralOption($url,$timeout,$headers=array(),$httpVersion=CURL_HTTP_VERSION_1_1)
    {
        curl_setopt($this->ch, CURLOPT_URL, $url);
        curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, true); //让CURL支持HTTPS访问
        curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 2);
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($this->ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($this->ch, CURLOPT_HTTP_VERSION, $httpVersion);
        // 启用debug获取更详细的连接信息，与CURLOPT_HEADER互斥
        curl_setopt($this->ch, CURLOPT_VERBOSE, 1);
        $this->verbose = fopen('php://temp', 'w+');
        curl_setopt($this->ch, CURLOPT_STDERR, $this->verbose);

        if ($headers && is_array($headers)) {
            $realHeader = [];
            foreach ($headers as $key => $val) {
                if (is_string($key)) {
                    $realHeader[] = $key. ': '. $val;
                } else {
                    $realHeader[] = $val;
                }
            }
            curl_setopt($this->ch, CURLOPT_HTTPHEADER, $realHeader);
        }
    }

    protected function execute()
    {
        $result = curl_exec($this->ch);

        // 记录详细的debug信息
        $this->curlInfo = curl_getinfo($this->ch);
        rewind($this->verbose);
        $this->curlInfo['verbose'] = stream_get_contents($this->verbose);
        $this->verbose = null;

        if ($result === false) {
            $this->errorCode = curl_errno($this->ch);
            $this->errorMsg = curl_error($this->ch);
            $this->curlInfo['error_code'] = $this->errorCode;
            $this->curlInfo['error_message'] = $this->errorMsg;
        }

        curl_reset($this->ch);
        return $result;
    }
}